<!DOCTYPE html>
<html lang="en">

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="css/style.css" rel="stylesheet">
</head>

<body>

</body>
<script>
    // //对 对象解构赋值  方法如下
    // let obj = {
    //     name: '张三',
    //     show: {
    //         cname: 'css',
    //         source: 90
    //     }
    // };
    // let { name, show: { cname, source } } = obj;
    // console.log(name, cname, source);
    // // 对象和方法的属性可以动态的添加或删除。
    // obj.age = 18;
    // console.log(JSON.stringify(obj, null, 2));
    // obj.showNmaeAge = function () {
    //     console.log(this.name, this.age);
    // };
    // obj.showNmaeAge();
    // //删除属性
    // delete obj.age;
    // console.log(JSON.stringify(obj, null, 2));
    // //使用默认值特性可以方便的对参数预设
    // function createElement(options) {
    //     let {
    //         width = '200px',
    //         height = '100px',
    //         backgroundColor = 'red'
    //     } = options;

    //     const h2 = document.createElement('h2');
    //     h2.style.width = width;
    //     h2.style.height = height;
    //     h2.style.backgroundColor = backgroundColor;
    //     document.body.appendChild(h2);
    // }
    // createElement({
    //     backgroundColor: 'pink',
    //     width: '500px',
    //     height: '600px'
    // });
    // //检查属性
    // console.log(obj.hasOwnProperty('name'));//true
    // //下面通过数组查看
    // let arr = ["后盾人"];
    // console.log(arr);
    // console.log(arr.hasOwnProperty("length")); //true
    // console.log(arr.hasOwnProperty("concat")); //false
    // console.log("concat" in arr); //true 先查询当前对象是否有 该属性 如果没有找到 再去父级去找
    // let obj1 = { name: '李四', kecheng: 'css' };
    // //设置obj为obj1的新原型
    // Object.setPrototypeOf(obj1, obj);//obj 成为 obj1 原型中的一个属性
    // console.log(obj1);
    // console.log(JSON.stringify(obj1, null, 2));
    // //获取属性名
    // let names = Object.getOwnPropertyNames(obj1);
    // console.log(names);//['name', 'kecheng']
    // //assgin以往我们使用类似jQuery.extend 等方法设置属性，现在可以使用 Object.assign 静态方法
    // // 从一个或多个对象复制属性
    // obj1 = Object.assign(obj1, obj);
    // console.log(obj1); //合并两个对象
    // //使用计算属性为文章定义键名
    // const lessons = [
    //     {
    //         title: "媒体查询响应式布局",
    //         category: "css"
    //     },
    //     {
    //         title: "FLEX 弹性盒模型",
    //         category: "css"
    //     },
    //     {
    //         title: "MYSQL多表查询随意操作",
    //         category: "mysql"
    //     }
    // ];
    // let lessonObj = lessons.reduce((obj, cur, index) => {
    //     //css-0: {title: '媒体查询响应式布局', category: 'css'}
    //     // console.log(obj, cur);
    //     obj[`${cur["category"]}-${index}`] = cur;
    //     return obj;
    // }, {});
    // console.log(lessonObj);
    // //遍历对象
    // console.log(Object.keys(lessons));//['0', '1', '2']
    // console.log(Object.values(lessons));// [{…}, {…}, {…}]
    // let obj2 = {
    //     name: '王五',
    //     age: 18,
    //     cname: "js"
    // };
    // console.log(Object.keys(obj2));//['name']
    // console.log(Object.values(obj2));// ['王五']
    // for (let key in obj2) {
    //     console.log(key, obj2[key]);//name 王五
    // }
    //属性名
    // for (const key of Object.keys(obj2)) {
    //     console.log(key);//name
    // }
    // //值
    // for (const key of Object.values(obj2)) {
    //     console.log(key);//王五
    // }
    // // 键值对
    // for (const array of Object.entries(obj2)) {
    //     console.log(array);//['name', '王五']
    // }
    // 对象的拷贝
    //浅拷贝
    //1.使用for in 拷贝
    // function show(obj) {
    //     console.log(JSON.stringify(obj, null, 2));
    // }
    // let obj2 = {
    //     name: '王五',
    //     age: 18,
    //     cname: "js"
    // };
    // let objTemp = {};
    // for (const key in obj2) {
    //     objTemp[key] = obj2[key];
    // }
    // objTemp.name = '五六';
    // show(objTemp);//"name": "五六"
    // show(obj2)//"name": "王五",
    // 2.Object.assign函数可简单的实现浅拷贝，它是将两个对象的属性叠加后面对象属性会覆盖前面对象同名属性。
    // let objTemp = {
    //     stu: Object.assign({}, obj2)
    // };
    // objTemp.stu.name = "七八";
    // show(objTemp);// "name": "七八",
    // show(obj2);// "name": "王五",
    // 3.展开语法实现浅拷贝
    // let objTemp = { ...obj2 };
    // objTemp.name = "九十";
    // show(objTemp);//  "name": "九十",
    // show(obj2);//"name": "王五",
    // 深拷贝  浅拷贝不能拷贝深层 对象
    // let obj2 = {
    //     name: '王五',
    //     age: 18,
    //     cname: "js",
    //     bzr: {
    //         name: '小明老师',
    //         age: 36
    //     },
    //     arr: []
    // };
    // function copy(obj) {
    //     let temp = {};
    //     for (let key in obj) {
    //         temp[key] = obj[key];
    //     }
    //     return temp;
    // }
    // let newObj = copy(obj2);
    // newObj.name = "深拷贝";
    // newObj.bzr.name = "朱老师";
    // newObj.arr.push("zhangsan");
    // show(newObj);//name": "深拷贝", 班主任没有拷贝成功 随着改变而改变
    // show(obj2);//"name": "王五",
    // // ^^^浅拷贝 深拷贝的区别
    //深拷贝
    // function copy(obj) {
    //     let temp = obj instanceof Array ? [] : {};
    //     for (let [k, v] of Object.entries(obj)) {
    //         temp[k] = typeof v == 'object' ? copy(v) : v;
    //     }
    //     return temp;
    // }
    // let newObj = copy(obj2);
    // newObj.bzr.name = "朱老师";
    // newObj.arr.push("zhangsan");
    // show(newObj);//"name": "朱老师",
    // show(obj2);// "name": "小明老师",  深拷贝成功
</script>
<!-- 构造函数 -->
<script>
    // "use strict";
    // //工厂函数 减少重复创建相同类型对象的代码 修改工厂函数的方法影响所有同类对象
    // function stu(name) {
    //     return {
    //         name,
    //         show() {
    //             console.log(this.name);
    //         }
    //     };
    // }
    // const lisi = stu('李四');
    // lisi.show();
    // const wangwu = stu('王五');
    // wangwu.show()
    // // 构造函数
    // // 构造函数名每个单词首字母大写即Pascal 命名规范
    // // this指当前创建的对象
    // // 不需要返回this系统会自动完成

    // // 需要使用new关键词生成对象
    // function Student(name) {
    //     this.name = name;
    //     this.show = function () {
    //         console.log(this.name);
    //     };
    // }
    // const lisi = new Student('李四');
    // lisi.show();
    // const wuangwu = new Student('王五');
    // wuangwu.show();
    // // 如果构造函数返回对象，实例化后的对象将是此对象
    // function ArrayObject(...values) {
    //     const arr = new Array();
    //     arr.push.apply(arr, values);
    //     arr.string = function (sym = "|") {
    //         return this.join(sym);
    //     };
    //     return arr;
    // }
    // const array = new ArrayObject(1, 2, 3);
    // console.log(array);//(3) [1, 2, 3, string: ƒ]
    // console.log(array.string("-"));//1-2-3
    // 属性特征 JS 中可以对属性的访问特性进行控制。
    // function show(item) {
    //     console.log(JSON.stringify(item, null, 2));
    // }
    // const user = {
    //     name: '老四',
    //     age: 36,
    //     position: '沐浴经理'
    // };
    // let desc = Object.getOwnPropertyDescriptor(user, 'name');
    // show(desc);
    // /**
    //  *  {
    //     "value": "老四",对象属性的默认值
    //     "writable": true,对象属性是否可修改
    //     "enumerable": true,对象属性是否可通过 for-in 循环，或 Object.keys() 读取
    //     "configurable": true 能否使用 delete、能否需改属性特性、或能否修改访问器属性
    //      }
    //  */
    // Object.defineProperty(user, "name", {
    //     value: "老吴",
    //     writable: false,
    //     enumerable: false,
    //     configurable: false
    // });
    // show(desc);//当吧其属性改为false 这不能对当前对象的属性 进行修改 遍历 删除
    // // Object.preventExtensions 禁止向对象添加属性
    // // Object.preventExtensions(user);
    // // user.money = 9999; //Cannot add property money, object is not extensible
    // // Object.isExtensible判断是否能向对象中添加属性
    // // console.log(Object.isExtensible(user)); //false ?Object.preventExtensions(user);
    // // Object.isSealed 如果对象是密封的则返回 true Object.seal()方法封闭一个对象，阻止添加新属性并将所有现有属性标记为
    // // Object.seal(user);
    // // // delete user.name; //Error
    // // console.log(Object.isSealed(user)); //true
    // //冻结对象
    // // Object.freeze 冻结对象后不允许添加、删除、修改属性，writable、configurable 都标记为false
    // Object.freeze(user);
    // // user.name = "老六";//Error
    // console.log(Object.isFrozen(user));

    //属性访问器
    //getter 方法用于获得属性值，setter 方法用于设置属性，这是 JS 提供的存取器特性即使用函数来管理属性。
    //用于避免错误的赋值 需要动态监测值的改变 属性只能在访问器和普通属性任选其一，不能共同存在
    // const user = {
    //     data: {
    //         name: '老四',
    //         age: 36,
    //         position: '沐浴经理',
    //     },
    //     set age(value) {
    //         if (typeof value != "number" || value > 100 || value < 10) {
    //             throw new Error("年龄格式错误");
    //         }
    //         this.data.age = value;
    //     },
    //     get age() {
    //         return `年龄是: ${this.data.age}`;
    //     }
    // };
    // user.age = 15;
    // console.log(user.age);
    // //还是可以通过user.data.age 改变
    // //定义symbol类型 来防止外部进行改变对象中的值
    // const DATA = Symbol();
    // class User {
    //     constructor(name, age) {
    //         this[DATA] = { name, age };
    //     }
    //     get name() {
    //         return this[DATA].name;
    //     }
    //     set name(value) {
    //         this[DATA].name = value;
    //     }
    //     get age() {
    //         return this[DATA].age;
    //     }
    //     set age(value) {
    //         this[DATA].age = value;
    //     }
    // }
    // let user = new User('老四', 36);
    // console.log(user.name);
    // user.name = '王五';
    // console.log(user.name);
    // console.log(user);

    //定义内部私有属性
    // const user = {
    //     set age(value) {
    //         if (typeof value != "number" || value > 100 || value < 10) {
    //             throw new Error("年龄格式错误");
    //         }
    //         this._age = value;
    //     },
    //     get age() {
    //         return `年龄是: ${this._age}`;
    //     }
    // };
    // user.age = 99;
    // console.log(user.age)
    //当set get与属性名重名 那个优先级更高？
    const user = {
        name: '老四',
        age: 36,
        position: '沐浴经理',
        set age(value) {
            if (typeof value != "number" || value > 100 || value < 10) {
                throw new Error("年龄格式错误");
            }
            // this.data.age = value + '--';
            console.log(value + "----优先级");
        },
        // get age() {
        //     return `年龄是: ${this.data.age}`;
        // }
    };
    //如果 set age优先级高的话  会返回 age -- 反之不会
    user.age = 99;//99----优先级  访问器的属性高于 user中的属性
    console.log(user.age)
</script>

</html>